// File: jmcomic-core/src/main/java/dev/jukomu/common/base/mapper/FileMapper.java
package dev.jukomu.common.base.mapper;

import dev.jukomu.common.util.file.FileUtils;

import java.io.IOException;
import java.util.Map;
import java.util.function.Function;

/**
 * 对应Python的MapperImpl，实现基于文件的键值对映射存储。
 * 键值对以指定分隔符存储在文件中，每行一个键值对。
 */
public class FileMapper extends AbstractDictMapper<String, String> {

    private final String mapFilePath;
    private String separator; // 键值对分隔符

    /**
     * 构造函数。
     *
     * @param mapFilePath 映射文件路径
     * @param separator   键值对分隔符
     */
    public FileMapper(String mapFilePath, String separator) {
        this.mapFilePath = mapFilePath;
        this.separator = separator;
    }

    @Override
    public void load() throws IOException {
        clearData(); // 先清空现有数据

        // 检查文件是否存在，如果不存在则创建空文件
        if (FileUtils.fileNotExists(mapFilePath)) {
            FileUtils.createFile(mapFilePath);
            return;
        }

        // 读取文件内容
        String content = FileUtils.readText(mapFilePath);
        for (String line : content.split("\n")) {
            line = line.trim();
            if (line.isEmpty()) {
                continue;
            }

            int splitWordIndex = line.indexOf(separator);
            if (splitWordIndex == -1) {
                continue; // 忽略没有分隔符的行
            }

            String key = line.substring(0, splitWordIndex).trim();
            String value = line.substring(splitWordIndex + separator.length()).trim();
            data.put(key, value);
        }
    }

    @Override
    public Object save(Function<Map<String, String>, Object> callback) throws IOException {
        if (data == null && callback == null) {
            return null; // 没有数据且没有回调，无需保存
        }

        makeSureLoaded(); // 确保数据已加载

        Map<String, String> dataToSave = data;
        Object callbackResult = null;

        if (callback != null) {
            // Python's callback can modify data and return it, or return something else.
            // Here, callback receives the data and can return an Object (e.g., Map or Collection of Entries).
            // We'll then use this returned object for writing.
            callbackResult = callback.apply(data);
            if (callbackResult instanceof Map) {
                dataToSave = (Map<String, String>) callbackResult;
            } else if (!(callbackResult instanceof Iterable)) { // If not Map or Iterable, we don't know how to save
                throw new IllegalArgumentException("Callback must return a Map or an Iterable for saving.");
            }
        }

        StringBuilder sb = new StringBuilder();
        if (callbackResult instanceof Iterable) { // If callback returned an Iterable (e.g., List of Map.Entry)
            for (Object item : (Iterable<?>) callbackResult) {
                if (item instanceof Map.Entry) {
                    Map.Entry<?, ?> entry = (Map.Entry<?, ?>) item;
                    sb.append(entry.getKey()).append(separator).append(entry.getValue()).append("\n");
                } else {
                    // Handle other Iterable item types if necessary, or throw error
                    throw new IllegalArgumentException("Iterable item must be a Map.Entry for saving.");
                }
            }
        } else { // Default: save the internal data Map
            for (Map.Entry<String, String> entry : dataToSave.entrySet()) {
                sb.append(entry.getKey()).append(separator).append(entry.getValue()).append("\n");
            }
        }

        FileUtils.writeText(mapFilePath, sb.toString());
        return callbackResult != null ? callbackResult : dataToSave; // Return what was saved
    }

    /**
     * 获取键值对分隔符。
     *
     * @return 分隔符
     */
    public String getSeparator() {
        return separator;
    }

    /**
     * 设置键值对分隔符。
     *
     * @param separator 新的分隔符
     */
    public void setSeparator(String separator) {
        this.separator = separator;
    }

    @Override
    public String toString() {
        return mapFilePath;
    }
}